/**
 * 手撕 shared_ptr
 *
 * 1.RAII 管理资源
 * 2.引用计数记录当前资源被多少个shared_ptr引用
 *      引用计数应该用new的方式申请，因为这个值被多个shared_ptr共享
 *      引用计数被多个shared_ptr共享，因此需要保证其增加减少操作的原子性
 */

#include <utility> // std::swap
#include <iostream>
#include <atomic>

#include <iostream>
#include <atomic>
#include <mutex>

template<typename T>
class SharedPtr
{
private:
    T* ptr;
    std::atomic<int>* ref_count;

public:
    // 默认构造函数
    SharedPtr(): ptr(nullptr), ref_count(nullptr) {}

    // 构造函数
    explicit SharedPtr(T* p): ptr(p), ref_count(new std::atomic<int>(1)) {}

    // 拷贝构造函数
    SharedPtr(const SharedPtr& other)
    {
        acquire(other);
    }

    // 移动构造函数
    SharedPtr(SharedPtr&& other) noexcept
    {
        move(std::move(other));
    }

    // 拷贝赋值操作符
    SharedPtr& operator=(const SharedPtr& other)
    {
        if (this != &other) {
            release();
            acquire(other);
        }
        return *this;
    }

    // 移动赋值操作符
    SharedPtr& operator=(SharedPtr&& other) noexcept
    {
        if (this != &other) {
            release();
            move(std::move(other));
        }
        return *this;
    }

    // 解引用操作符
    T& operator*() const
    {
        return *ptr;
    }

    // 指针访问操作符
    T* operator->() const
    {
        return ptr;
    }

    // 获取原始指针
    T* get() const
    {
        return ptr;
    }

    // 获取引用计数
    int use_count() const
    {
        return ref_count ? ref_count->load() : 0;
    }

    // 析构函数
    ~SharedPtr()
    {
        release();
    }

private:
    void acquire(const SharedPtr& other)
    {
        ptr = other.ptr;
        ref_count = other.ref_count;
        if (ref_count) {
            ref_count->fetch_add(1, std::memory_order_relaxed);
        }
    }

    void release()
    {
        if (ref_count &&
            ref_count->fetch_sub(1, std::memory_order_acq_rel) == 1) {
            delete ptr;
            delete ref_count;
        }
        ptr = nullptr;
        ref_count = nullptr;
    }

    void move(SharedPtr&& other)
    {
        ptr = other.ptr;
        ref_count = other.ref_count;
        other.ptr = nullptr;
        other.ref_count = nullptr;
    }
};

// 测试代码
int main()
{
    SharedPtr<int> sp1(new int(10));
    SharedPtr<int> sp2 = sp1;

    std::cout << "sp1 use count: " << sp1.use_count() << std::endl;
    std::cout << "sp2 use count: " << sp2.use_count() << std::endl;

    SharedPtr<int> sp3;
    sp3 = sp1;

    std::cout << "sp1 use count: " << sp1.use_count() << std::endl;
    std::cout << "sp3 use count: " << sp3.use_count() << std::endl;

    return 0;
}
